home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat España 20
/
macformat_20.iso
/
mac
/
Shareware
/
Desarrolladores
/
Sprite Animation Toolkit 2.3.8
/
Add-ons
/
Load faces
/
FastLoad.p
< prev
Wrap
Text File
|
1996-06-23
|
15KB
|
378 lines
unit FastLoad;
{This unit holds routines for loading faces pointing into parts of offscreen buffers. This is useful for}
{loading large numbers of faces really fast (since it is drawn in one operation, and much fewer Memory}
{Management and Resource Manager operations are needed), but also for odd sprites that "peek" into}
{other parts of offscreens.}
{/Ingemar Ragnemalm december 1995 (Revised may 1996)}
interface
uses
{$ifc UNDEFINED THINK_PASCAL}
Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile,{}
GestaltEqu, Files, Errors, Devices,
{$endc}
SAT;
type
FaceArr = array[0..1000] of Face;
FaceArrPtr = ^FaceArr;
{PeekFaceInOffscreen: A variation on BuildFaceInOffscreen, intended for special effects. It doesn't}
{allocate the face data, but demands that the face already exists. Use it for making a sprite face}
{peek into some image buffer other than its own private one.}
procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
needsRegion, makeRowList: Boolean);
{BuildFaceInOffscreen: This is the heart of FastLoad. It builds a face pointing into some image of}
{your choice.}
procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect;{}
needsRegion, makeRowList: Boolean);
{LoadFaceArray and Load2DFaceArray: High-level functions, for loading faces arrange in arrays}
{in PICTs.}
function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
needsRegion, makeRowList: Boolean): FaceArrPtr;
function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer;{}
facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
{Note: The two Booleans needsRegion and makeRowList, used in all routines above, tell whether you}
{want certain extra data in the face. Set needsRegion to true if you want to run your program to run}
{as fast as possible WITHOUT blitters, using only QuickDraw. Set makeRowList of you want it to run}
{with optimal speed WITH blitters. If both are false, it will load extremely fast, but the animation may}
{not run quite as fast.}
{This routine is in SAT.lib, but not in the interface files! It is for internal use by the unit.}
procedure SATMakeRowList (portRect: Rect; baseAddr: Ptr; rowBytes: integer; var rows: Ptr; depth: Integer);
implementation
type
BMPtr = ^BitMap;
FourBitStuff = record
evenData, oddData: Ptr;
oddMask: BitMap;
oddRowBytes: integer;
destRect: Rect; {Behövs för safe}
oddRows, oddMaskRows: Ptr;
end;
FourBitPtr = ^FourBitStuff;
{BuildFaceInOffscreen builds a face that points into two offscreen imgaes, one for the image data}
{and one for the mask. This can be used for loading faces quickly, but also for making weirds}
{sprites who peek into other parts of the screen.}
{}
{This will probably NEVER get really good in 4-bit color.}
procedure BuildFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
begin
theFace.iconMask.baseAddr := Ptr(Longint(maskOff.baseAddr) + Longint(maskOff.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
theFace.iconMask.rowBytes := maskOff.rowBytes;
theFace.iconMask.bounds := bounds;
OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
if gSAT.initDepth = 1 then
begin
theFace.colorData := NewPtrClear(sizeOf(BitMap));
if theFace.colorData <> nil then
begin
BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
if makeRowList then
SATMakeRowList(bounds, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
end;
end
else if gSAT.initDepth = 4 then
{4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
{since it is better than crashing.}
begin
theFace.colorData := NewPtrClear(sizeof(FourBitStuff));
if theFace.colorData <> nil then
with FourBitPtr(theFace.colorData)^ do
begin
theFace.rowBytes := imageOff.rowBytes;
evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
if makeRowList then
SATMakeRowList(bounds, evenData, theFace.rowBytes, theFace.rows, 4);
oddRowBytes := imageOff.rowBytes;
oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
destRect := theFace.iconMask.bounds;
{OffsetRect(destRect, 1, 0);}
if makeRowList then
SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
{oddMask.bounds.left := 0; {Måste ha origo rätt!}
oddRows := nil;
oddMaskRows := nil;
if makeRowList then
SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
if makeRowList then
SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
end;
end
else
begin
theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
if makeRowList then
SATMakeRowList(bounds, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
if makeRowList then
SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
end;
theFace.rowBytes := imageOff.rowBytes;
theFace.next := nil;
{Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
{giving up the safety backdoor! Another option is to use on region for several masks, when we know some masks}
{are equal.}
if needsRegion then
begin
theFace.maskRgn := NewRgn;
if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
;
end
else
theFace.maskRgn := nil;
{Arrays of row starts. I skip them for now, though they are advisable when using blitters. They are pretty}
{easy to make though: just a pointer to an array of pointers, where each points to the first byte in each row.}
theFace.rows := nil;
theFace.maskRows := nil;
{Hooks that we don't use here:}
theFace.redrawProc := nil;
theFace.drawProc := nil;
end; {BuildFaceInOffscreen}
{PeekFaceInOffscreen is very similar to BuildFaceInOffscreen, but doesn't build the face, but just changes its}
{pointers to another place in the offscreens, in order to change where it points. You can then have it pointing}
{anywhere, into other ports, to the screen etc. However, if the memory it points to changes, sprites using}
{the face may have to set their "dirty" flag in order to work with SATRun2!}
{The only difference to BuildFaceInOffscreen is that it doesn't allocate pointers.}
procedure PeekFaceInOffscreen (var theFace: Face; imageOff, maskOff: SATPort; bounds: Rect; needsRegion, makeRowList: Boolean);
begin
theFace.iconMask.baseAddr := Ptr(Longint(maskOff.baseAddr) + Longint(maskOff.rowBytes) * bounds.top + bounds.left div 8); {32 pixels wide = 4 bytes wide in B/W}
theFace.iconMask.rowBytes := maskOff.rowBytes;
theFace.iconMask.bounds := bounds;
OffsetRect(theFace.iconMask.bounds, -theFace.iconMask.bounds.left, -theFace.iconMask.bounds.top);
if gSAT.initDepth = 1 then
begin
{theFace.colorData := NewPtrClear(sizeOf(BitMap));}
if theFace.colorData <> nil then
begin
BMPtr(theFace.colorData)^.bounds := theFace.iconMask.bounds;
BMPtr(theFace.colorData)^.rowBytes := imageOff.rowBytes;
BMPtr(theFace.colorData)^.baseAddr := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left div 8);
if makeRowList then
SATMakeRowList(bounds, BMPtr(theFace.colorData)^.baseAddr, BMPtr(theFace.colorData)^.rowBytes, theFace.rows, 1);
end;
end
else if gSAT.initDepth = 4 then
{4-bit isn't good, since we have no shifted version of the offscreen being pointed into. I support it halfway just}
{since it is better than crashing.}
begin
{theFace.colorData := NewPtrClear(sizeof(FourBitStuff));}
if theFace.colorData <> nil then
with FourBitPtr(theFace.colorData)^ do
begin
theFace.rowBytes := imageOff.rowBytes;
evenData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
if makeRowList then
SATMakeRowList(bounds, evenData, theFace.rowBytes, theFace.rows, 4);
oddRowBytes := imageOff.rowBytes;
oddData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
destRect := theFace.iconMask.bounds;
{OffsetRect(destRect, 1, 0);}
if makeRowList then
SATMakeRowList(destRect, oddData, oddRowBytes, oddRows, 4);
BlockMove(@theFace.iconMask, @oddMask, SizeOf(BitMap));
{oddMask.bounds.left := 0; {Måste ha origo rätt!}
oddRows := nil;
oddMaskRows := nil;
if makeRowList then
SATMakeRowList(oddMask.bounds, oddMask.baseAddr, oddMask.rowBytes, oddMaskRows, 1);
if makeRowList then
SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
end;
end
else
begin
theFace.colorData := Ptr(Longint(imageOff.baseAddr) + Longint(imageOff.rowBytes) * bounds.top + bounds.left * gSAT.initDepth div 8);
if makeRowList then
SATMakeRowList(bounds, theFace.colorData, theFace.rowBytes, theFace.rows, gSAT.initDepth);
if makeRowList then
SATMakeRowList(theFace.iconMask.bounds, theFace.iconMask.baseAddr, theFace.iconMask.rowBytes, theFace.maskRows, 1);
end;
theFace.rowBytes := imageOff.rowBytes;
theFace.next := nil;
{Build region. This is time consuming, but can be skipped if we only draw with blitters - but that means}
{giving up the safety backdoor! Another option is to use on region for several masks, when we know}
{some masks are equal.}
if needsRegion then
begin
if theFace.maskRgn = nil then
theFace.maskRgn := NewRgn;
if noErr <> BitMapToRegion(theFace.maskRgn, theFace.iconMask) then
;
end
else
theFace.maskRgn := nil;
{Arrays of row starts. I skip them for now, though they are advisable when using blitters. They are pretty}
{easy to make though: just a pointer to an array of pointers, where each points to the first byte in each row.}
theFace.rows := nil;
theFace.maskRows := nil;
{Hooks that we don't use here:}
theFace.redrawProc := nil;
theFace.drawProc := nil;
end; {PeekFaceInOffscreen}
{CreateBWOffscreen is useful for creating a B/W offscreeen buffer for masks}
procedure CreateBWOffscreen (var portP: SATPort; frame: Rect);
var
savePort: GrafPtr;
begin
GetPort(savePort);
portP.device := nil;
portP.port := GrafPtr(NewPtr(sizeof(GrafPort)));
OpenPort(portP.port);
portP.port^.portRect := frame;
portP.port^.portBits.bounds := portP.port^.portRect;
RectRgn(portP.port^.visRgn, frame);
ClipRect(frame);
portP.port^.portBits.rowBytes := longint(((portP.port^.portRect.right - portP.port^.portRect.left + 31) div 32) * 4);
portP.port^.portBits.baseAddr := NewPtr(portP.port^.portBits.rowBytes * longint(portP.port^.portRect.bottom - portP.port^.portRect.top));
SetPort(portP.port);
EraseRect(portP.port^.portRect);
portP.baseAddr := portP.port^.portBits.baseAddr;
portP.bounds := portP.port^.portBits.bounds;
portP.rowBytes := portP.port^.portBits.rowBytes;
{with portP.port^ do}
{SATMakeRowList(portRect, portBits.baseAddr, portBits.rowBytes, portP.rows, 1);}
SetPort(savePort);
end; {CreateBWOffscreen}
{LoadFaceArray loads a set of faces to a one-dimensional array of faces, arranged vertically in a PICT}
{resource. You can easily extend it to 2-dimensional arrays if you like.}
{NOT TESTED!}
function LoadFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
needsRegion, makeRowList: Boolean): FaceArrPtr;
var
fr, mr: Rect;
facesOff, masksOff: SATPort;
i: Integer;
faces: FaceArrPtr;
facesPict, masksPict: PicHandle;
bounds: Rect;
begin
LoadFaceArray := nil;
faces := FaceArrPtr(NewPtr(SizeOf(Face) * numFaces));
if faces = nil then
Exit(LoadFaceArray);
facesPict := GetPicture(facesPictId);
masksPict := GetPicture(masksPictID);
fr := facesPict^^.picFrame;
OffsetRect(fr, -fr.left, -fr.top);
SATMakeOffscreen(facesOff, fr);
SATSetPort(facesOff);
DrawPicture(facesPict, fr);
mr := masksPict^^.picFrame;
OffsetRect(mr, -mr.left, -mr.top);
CreateBWOffscreen(masksOff, mr);
SATSetPort(masksOff);
DrawPicture(masksPict, mr);
ReleaseResource(Handle(facesPict));
ReleaseResource(Handle(masksPict));
{This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures!}
for i := 0 to numFaces - 1 do
begin
SetRect(bounds, 0, i * sizeV, sizeH, (i + 1) * sizeV);
BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
end;
LoadFaceArray := faces;
end; {LoadFaceArray}
function Load2DFaceArray (facesPictId, masksPictID: Integer; numFaces, sizeH, sizeV: Integer; {}
facesPerRow: Integer; needsRegion, makeRowList: Boolean): FaceArrPtr;
var
fr, mr: Rect;
facesOff, masksOff: SATPort;
i, h, v: Integer;
faces: FaceArrPtr;
facesPict, masksPict: PicHandle;
bounds: Rect;
begin
Load2DFaceArray := nil;
faces := FaceArrPtr(NewPtr(SizeOf(Face) * numFaces));
if faces = nil then
Exit(Load2DFaceArray);
facesPict := GetPicture(facesPictId);
masksPict := GetPicture(masksPictID);
fr := facesPict^^.picFrame;
OffsetRect(fr, -fr.left, -fr.top);
SATMakeOffscreen(facesOff, fr);
SATSetPort(facesOff);
DrawPicture(facesPict, fr);
mr := masksPict^^.picFrame;
OffsetRect(mr, -mr.left, -mr.top);
CreateBWOffscreen(masksOff, mr);
SATSetPort(masksOff);
DrawPicture(masksPict, mr);
ReleaseResource(Handle(facesPict));
ReleaseResource(Handle(masksPict));
{This routine assumes that we have numFaces faces of sizeH*sizeV pixels with masks in the two pictures,}
{arranged with facesPerRow faces per row!}
for i := 0 to numFaces - 1 do
begin
h := i mod facesPerRow; {0..facesPerRow-1}
v := i div facesPerRow; {0 and up}
SetRect(bounds, h * sizeH, v * sizeV, (h + 1) * sizeH, (v + 1) * sizeV);
BuildFaceInOffscreen(faces^[i], facesOff, masksOff, bounds, needsRegion, makeRowList);
end;
Load2DFaceArray := faces;
end; {Load2DFaceArray}
end.